<template>
  <el-dialog
    v-model="visible"
    title="设置"
    class="h-80vh max-w-1280px flex-col"
    body-class="flex-auto"
    width="80%"
    append-to-body
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    :show-close="false"
  >
    <div class="flex-col">
      <el-divider content-position="left">ollama服务地址</el-divider>
      <div class="flex-center gap-12px max-w-500px">
        <el-autocomplete
          v-model.trim="modelStore.host"
          :fetch-suggestions="querySearch"
          :trigger-on-focus="!modelStore.host"
          placeholder="http://或https://开头，不能携带任何query参数"
        ></el-autocomplete>
        <el-button type="primary" @click="handleChangeHost">应用</el-button>
      </div>
      <el-divider content-position="left">拉取新模型</el-divider>
      <div class="flex-center gap-12px max-w-500px">
        <el-input v-model.trim="modelName" placeholder="模型名称，如deepseek-r1:1.5b"></el-input>
        <el-button type="primary" @click="handlePull">拉取</el-button>
      </div>
      <el-divider content-position="left">模型列表</el-divider>
      <el-table class="flex-auto" :data="modelStore.list" border @cell-dblclick="handleCopy" stripe>
        <el-table-column type="expand">
          <template #default="{ row }">
            <el-descriptions size="small" border class="mx-1rem">
              <el-descriptions-item
                v-for="(item, index) in Object.entries(row.details)"
                :key="index"
                :label="item[0]"
                >{{ item[1] }}</el-descriptions-item
              >
            </el-descriptions>
          </template>
        </el-table-column>
        <el-table-column prop="name" width="250px" label="模型名称" show-overflow-tooltip>
          <template #default="{ row }">
            <div class="flex-center gap-12px">
              <div class="font-700">{{ row.name.split(':')[0] }}</div>
              <el-tag>{{ row.name.split(':')?.[1] }}</el-tag>
            </div>
          </template>
        </el-table-column>
        <el-table-column
          prop="digest"
          label="摘要"
          width="150px"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column
          prop="size"
          label="大小"
          :formatter="(row: ModelResponse) => formatBytes(row.size, 2)"
          width="100px"
        >
        </el-table-column>
        <el-table-column
          prop="modified_at"
          label="修改时间"
          :formatter="formatTime"
          width="164px"
        ></el-table-column>
        <el-table-column prop="status" label="状态">
          <template #default="{ row }">
            <el-tag
              v-if="row.status === 'success' || row.status === 'cancel'"
              :type="row.status === 'success' ? 'success' : 'info'"
              >{{ row.status === 'success' ? '已下载' : '已停止' }}</el-tag
            >
            <div v-else>
              <el-text :type="row.status === 'error' ? 'danger' : 'info'" tag="div"
                >消息：{{ row.msg }}</el-text
              >
              <el-text type="info" tag="div">已完成：{{ formatBytes(row.completed, 2) }}</el-text>
              <el-text type="info" tag="div">速度：{{ formatBytes(row.speed, 2, '/s') }}</el-text>
            </div>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="96px">
          <template #default="{ row }: { row: ModelList }">
            <el-button-group class="flex-c-c">
              <el-button
                v-if="row.status === 'success'"
                @click="modelStore.pullModel(row.name)"
                text
                circle
              >
                <el-icon size="20px"> <Refresh /> </el-icon>
              </el-button>
              <el-button
                v-if="row.status === 'cancel' || row.status === 'error'"
                type="info"
                @click="modelStore.pullModel(row.name)"
                text
                circle
              >
                <el-icon size="20px"><VideoPlay /></el-icon>
              </el-button>
              <el-button v-if="row.status === 'loading'" @click="handlePause(row)" text circle>
                <el-icon size="20px"> <VideoPause /> </el-icon>
              </el-button>
              <el-button
                type="danger"
                @click="handleDel(row)"
                text
                circle
                :disabled="row.status === 'loading'"
              >
                <el-icon size="20px"> <Delete /> </el-icon>
              </el-button>
            </el-button-group>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <template #footer>
      <el-button type="primary" @click="handleClose">确定</el-button>
    </template>
  </el-dialog>
</template>
<script lang="ts" setup>
import { useClipboard, useStorage } from '@vueuse/core'
import { dayjs, type TableColumnCtx } from 'element-plus'
import { Delete, Refresh, VideoPause, VideoPlay } from '@element-plus/icons-vue'
import type { ModelResponse } from 'ollama'
import { useModelStore, type ModelList } from '@/stores/model'
import { formatBytes } from '@/utils/formatter'
defineOptions({ name: 'ModelManage' })
const modelStore = useModelStore()
const visible = defineModel<boolean>()

const hostList = useStorage('hostList', [{ value: 'http://localhost:11434' }])
const querySearch = (queryString: string, cb: (list: { value: string }[]) => void) => {
  const results = queryString ? hostList.value.filter(createFilter(queryString)) : hostList.value
  cb(results)
}

const createFilter = (queryString: string) => {
  return (item: { value: string }) => {
    return item.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
  }
}
const handleChangeHost = () => {
  modelStore.changeHost()
}

const modelName = ref('')
const handlePull = () => {
  let name = modelName.value.trim()
  if (!name) {
    ElMessage.error('请输入模型名称')
    return
  }
  if (!modelName.value.includes(':')) {
    name = `${modelName.value}:latest`
  }
  modelStore.pullModel(name)
  modelName.value = ''
}
const { copy } = useClipboard()
// 双击复制
const handleCopy = (row: ModelResponse, col: TableColumnCtx<ModelResponse>) => {
  const { property } = col
  if (['name', 'digest'].includes(property)) {
    copy(String(row[property as keyof ModelResponse]))
      .then(() => {
        ElMessage.success(`复制成功`)
      })
      .catch((err) => {
        ElMessage.error('复制失败', err)
      })
  }
}
const formatTime = (row: ModelResponse) => {
  return dayjs(row.modified_at).format('YYYY-MM-DD HH:mm:ss')
}
/**
 * 暂停或取消下载
 * @param row
 */
const handlePause = (row: ModelList) => {
  row.aborter?.abort()
  row.aborter = undefined
  row.status = 'cancel'
}
const handleDel = async (row: ModelResponse) => {
  const confirm = await ElMessageBox.confirm(`确定要删除模型 ${row.name} 吗？`, '提示', {
    type: 'warning',
  })
  if (confirm === 'confirm') {
    modelStore.delModel(row.name)
  }
}

const handleClose = () => {
  if (!modelStore.host) {
    ElMessage.error('请先设置ollama服务地址')
    return
  }
  visible.value = false
}
</script>
<style lang="scss"></style>
